package xiaomogu.task_engine.core.biz.impl;

import xiaomogu.task_engine.core.biz.ExecutorBiz;
import xiaomogu.task_engine.core.biz.model.*;
import xiaomogu.task_engine.core.enums.BlockStrategy;
import xiaomogu.task_engine.core.executor.JobExecutor;
import xiaomogu.task_engine.core.handler.JobHandler;
import xiaomogu.task_engine.core.log.JobFileAppender;
import xiaomogu.task_engine.core.thread.JobThread;

import java.util.Date;


public class ExecutorBizImpl implements ExecutorBiz {
    @Override
    public Response<String> beat() {
        return Response.SUCCESS;
    }

    @Override
    public Response<String> idleBeat(IdleBeatParam idleBeatParam) {
        // isRunningOrHasQueue
        boolean isRunningOrHasQueue = false;
        JobThread jobThread = JobExecutor.loadJobThread(idleBeatParam.getJobId());
        if (jobThread != null && jobThread.isRunningOrHasQueue()) {
            isRunningOrHasQueue = true;
        }

        if (isRunningOrHasQueue) {
            return new Response<String>(Response.FAIL_CODE, "job thread is running or has trigger queue.");
        }
        return Response.SUCCESS;
    }

    @Override
    public Response<String> run(TriggerParam triggerParam) {
        // load old：jobHandler + jobThread
        JobThread jobThread = JobExecutor.loadJobThread(triggerParam.getJobId());
        JobHandler jobHandler = jobThread != null ? jobThread.getJobHandler() : null;
        String removeOldReason = null;
        // new jobhandler
        JobHandler newJobHandler = JobExecutor.loadJobHandler(triggerParam.getExecutorHandler());
        // valid old jobThread
        if (jobThread != null && jobHandler != newJobHandler) {
            // change handler, need kill old thread
            removeOldReason = "change jobhandler or glue type, and terminate the old job thread.";

            jobThread = null;
            jobHandler = null;
        }

        // valid handler
        if (jobHandler == null) {
            jobHandler = newJobHandler;
            if (jobHandler == null) {
                return new Response<String>(Response.FAIL_CODE, "job handler [" + triggerParam.getExecutorHandler() + "] not found.");
            }
        }

        // executor block strategy
        if (jobThread != null) {
            BlockStrategy blockStrategy = BlockStrategy.match(triggerParam.getExecutorBlockStrategy(), null);
            if (BlockStrategy.DISCARD_LATER == blockStrategy) {
                // discard when running
                if (jobThread.isRunningOrHasQueue()) {
                    return new Response<String>(Response.FAIL_CODE, "block strategy effect：" + BlockStrategy.DISCARD_LATER.getTitle());
                }
            } else if (BlockStrategy.COVER_EARLY == blockStrategy) {
                // kill running jobThread
                if (jobThread.isRunningOrHasQueue()) {
                    removeOldReason = "block strategy effect：" + BlockStrategy.COVER_EARLY.getTitle();

                    jobThread = null;
                }
            } else {
                // just queue trigger
            }
        }

        // replace thread (new or exists invalid)
        if (jobThread == null) {
            jobThread = JobExecutor.registJobThread(triggerParam.getJobId(), jobHandler, removeOldReason);
        }

        // push data to queue
        Response<String> pushResult = jobThread.pushTriggerQueue(triggerParam);
        return pushResult;
    }

    @Override
    public Response<String> kill(KillParam killParam) {
        // kill handlerThread, and create new one
        JobThread jobThread = JobExecutor.loadJobThread(killParam.getJobId());
        if (jobThread != null) {
            JobExecutor.removeJobThread(killParam.getJobId(), "scheduling center kill job.");
            return Response.SUCCESS;
        }

        return new Response<String>(Response.SUCCESS_CODE, "job thread already killed.");
    }

    @Override
    public Response<LogResult> log(LogParam logParam) {
        // log filename: logPath/yyyy-MM-dd/9999.log
        String logFileName = JobFileAppender.makeLogFileName(new Date(logParam.getLogDateTim()), logParam.getLogId());

        LogResult logResult = JobFileAppender.readLog(logFileName, logParam.getFromLineNum());
        return new Response<LogResult>(logResult);
    }

}
